#include <Fat_Func.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stm32f10x.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_dac.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_tim.h>
#include <Config.h>
#include <DAC_STM32.h>

unsigned char *Sample_Current;
unsigned char *Sample_Next;

#define dac_buff_size 4096
static uint16_t dac_buff[dac_buff_size];
static unsigned int pos_buff = 0;
static unsigned int time_scale = 0;
static unsigned int time_scale_tmp = 0;
static unsigned int count_buff_element = 0;
//---for play WAV----------------------------------------
#define WAV_Buff_size dac_buff_size
#define WAV_Buff dac_buff
static unsigned int WAV_Buff_out = 0;
static unsigned int WAV_Buff_in = 0;
static uint8_t flag_EndOfFile = 0;
static unsigned int flag_play_wav = 0;
static WAV_INFO WAV_info_play;
unsigned int flag_1st_element = 1;
;
//-------------------------------------------------------

unsigned int shift_pos(unsigned int pos) {
	pos++;
	if (pos == WAV_Buff_size) {
		pos = 0;
	}
	return pos;
}
unsigned int shift_pos_back(unsigned int pos) {
	if (pos == 0) {
		pos = WAV_Buff_size - 1;
	}
	pos--;
	return pos;
}

unsigned int add_buffer(uint16_t element) {
	unsigned int tmp = shift_pos(WAV_Buff_in);
	if (tmp != WAV_Buff_out) {
		WAV_Buff[WAV_Buff_in] = element;
		WAV_Buff_in = tmp;
		return 1;
	} else {
		return 0;
	}
}

uint16_t get_buffer(void) {
	uint16_t tmp = WAV_Buff[WAV_Buff_out];
	WAV_Buff[WAV_Buff_out] = 0;
	if (WAV_Buff_out != WAV_Buff_in) {
		WAV_Buff_out = shift_pos(WAV_Buff_out);
	}
	return tmp;
}

void DAC1_Configuration(void) {
	DAC_InitTypeDef DAC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;
//		DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Triangle;
//		DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude
//				= DAC_TriangleAmplitude_1;
	DAC_InitStructure.DAC_WaveGeneration = DAC_Wave_Noise;
	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits11_0;
	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
	DAC_Init(DAC_Channel_1, &DAC_InitStructure);
	DAC_Cmd(DAC_Channel_1, ENABLE);
}

void DAC1_Out(uint16_t value) {
	DAC_SetChannel1Data(DAC_Align_12b_R, value);
}

//---for play WAV---------------------------------------------------------------------
void DAC1_stop_WAV(WAV_INFO wav_info)
{
	Switch_timer_DAC_IRQ(DISABLE);
	Switch_timer_feedWAV_IRQ(DISABLE);
	WAV_Buff_out = 0;
	WAV_Buff_in = 0;
	flag_1st_element = 1;
	flag_play_wav = 0;
	CloseWAVFile(wav_info);
}

void DAC1_play_WAV(WAV_INFO wav_info) {
	Switch_timer_DAC_IRQ(DISABLE);
	Switch_timer_feedWAV_IRQ(DISABLE);
	WAV_info_play = wav_info;
	time_scale = 1 * 1000000 / wav_info.SampleRate;
	OUTPUT_USARTTerm;
	printf("time_scale = %u\r\n", time_scale);
	WAV_Buff_out = 0;
	WAV_Buff_in = 0;
	flag_1st_element = 1;
	while ((flag_EndOfFile == 0)) {
		if (add_buffer(ReadWAVFile(WAV_info_play, &flag_EndOfFile)) == 0) {
			OUTPUT_USARTTerm;
			puts("add buff fail\r\n");
			break;
		}
	}
	OUTPUT_USARTTerm;
	printf("WAV_Buff_in = %u\r\n", WAV_Buff_in);
	flag_play_wav = 1;
	timer_DAC_config(time_scale);
	timer_feedWAV_config(time_scale);
	Switch_timer_DAC_IRQ(ENABLE);
	Switch_timer_feedWAV_IRQ(ENABLE);
	OUTPUT_USARTTerm;
	puts("prepare done\r\n");
}
//------------------------------------------------------------------------------------

void DAC1_generate_const(unsigned int level) {
	Switch_timer_DAC_IRQ(DISABLE);
	if ((level > 100) || (level < 1)) {
		OUTPUT_USARTTerm;
		puts("out of level, auto set level of DAC output to 100 % of VDD\r\n");
		DAC1_Out(4095);
		OUTPUT_USARTTerm;
		printf("level get: %u\r\n", 100);
	} else {
		DAC1_Out(level * 4095 / 100);
		OUTPUT_USARTTerm;
		printf("level get: %u\r\n", level);
	}
}

void DAC1_generate_sine(unsigned int freq) {
	if ((freq < 1) || (freq > 20000)) {
		OUTPUT_USARTTerm;
		puts("out of level, auto set frequency to 1 Hz\r\n");
		freq = 1;
	}
	unsigned int pos;
	unsigned long T = 1 * 1000000 / freq; //T in micro sec
	Switch_timer_DAC_IRQ(DISABLE);
	if (T <= dac_buff_size) {
		time_scale = 1;
		count_buff_element = T;
		for (pos = 0; pos < T; pos++) {
			dac_buff[pos] = (unsigned int) (2047 + 2047 * sin((pi * (double) (2
					* freq * pos)) / 1000000));
		}
	} else {
		double scale = ((double) T / dac_buff_size);
		for (pos = 0; pos < dac_buff_size; pos++) {
			dac_buff[pos] = (unsigned int) (2047 + 2047 * sin((pi * (double) (2
					* freq * pos * scale)) / 1000000));
		}
		time_scale = (unsigned int) scale;
		count_buff_element = dac_buff_size;
	}
	timer_DAC_config(time_scale);
	pos_buff = 0;
	time_scale_tmp = 0;
	Switch_timer_DAC_IRQ(ENABLE);
}

void DAC1_generate_square(unsigned int freq) {
	if ((freq < 1) || (freq > 20000)) {
		OUTPUT_USARTTerm;
		puts("out of level, auto set frequency to 1 Hz\r\n");
		freq = 1;
	}
	unsigned int pos;
	unsigned long T = 1 * 1000000 / freq; //T in micro sec
	Switch_timer_DAC_IRQ(DISABLE);
	if (T <= dac_buff_size) {
		time_scale = 1;
		count_buff_element = T;
		for (pos = 0; pos < T; pos++) {
			if (pos * 2 < T) {
				dac_buff[pos] = 4095;
			} else {
				dac_buff[pos] = 0;
			}
		}
	} else {
		double scale = ((double) T / dac_buff_size);
		for (pos = 0; pos < dac_buff_size; pos++) {
			if (pos * 2 < dac_buff_size) {
				dac_buff[pos] = 4095;
			} else {
				dac_buff[pos] = 0;
			}
		}
		time_scale = (unsigned int) scale;
		count_buff_element = dac_buff_size;
	}
	timer_DAC_config(time_scale);
	pos_buff = 0;
	time_scale_tmp = 0;
	Switch_timer_DAC_IRQ(ENABLE);
}
void DAC1_generate_triangular(unsigned int freq) {
	if ((freq < 1) || (freq > 20000)) {
		OUTPUT_USARTTerm;
		puts("out of level, auto set frequency to 1 Hz\r\n");
		freq = 1;
	}
	unsigned int pos;
	unsigned long T = 1 * 1000000 / freq; //T in micro sec
	Switch_timer_DAC_IRQ(DISABLE);
	if (T <= dac_buff_size) {
		time_scale = 1;
		count_buff_element = T;
		for (pos = 0; pos < T; pos++) {
			if (pos * 2 < T) {
				dac_buff[pos] = 4095 * pos * 2 / T;
			} else {
				dac_buff[pos] = 4095 * 2 - 4095 * pos * 2 / T;
			}
		}
	} else {
		double scale = ((double) T / dac_buff_size);
		for (pos = 0; pos < dac_buff_size; pos++) {
			if (pos * 2 < dac_buff_size) {
				dac_buff[pos] = 4095 * pos * 2 / dac_buff_size;
			} else {
				dac_buff[pos] = 4095 * 2 - 4095 * pos * 2 / dac_buff_size;
			}
		}
		time_scale = (unsigned int) scale;
		count_buff_element = dac_buff_size;
	}
	timer_DAC_config(time_scale);
	pos_buff = 0;
	time_scale_tmp = 0;
	Switch_timer_DAC_IRQ(ENABLE);
}
void DAC1_generate_squarecustom(unsigned int Ton, unsigned int Toff) {
	if ((Ton < 100) || (Ton > 2000)) {
		OUTPUT_USARTTerm;
		puts("out of level, auto set Ton to 100ms\r\n");
		Ton = 100;
	}
	if (Toff > 2000) {
		OUTPUT_USARTTerm;
		puts("out of level, auto set Toff to 0ms\r\n");
		Toff = 0;
	}
	unsigned int pos;
	unsigned long T = (Ton + Toff) * 1000;
	Switch_timer_DAC_IRQ(DISABLE);
	if (T <= dac_buff_size) {
		time_scale = 1;
		count_buff_element = T;
		for (pos = 0; pos < T; pos++) {
			if (pos < Ton) {
				dac_buff[pos] = 4095;
			} else {
				dac_buff[pos] = 0;
			}
		}
	} else {
		double scale = ((double) T / dac_buff_size);
		unsigned int Pos_revert = (Ton * 1000 * dac_buff_size) / T;
		for (pos = 0; pos < dac_buff_size; pos++) {
			if (pos < Pos_revert) {
				dac_buff[pos] = 4095;
			} else {
				dac_buff[pos] = 0;
			}
		}
		time_scale = (unsigned int) scale;
		count_buff_element = dac_buff_size;
	}
	timer_DAC_config(time_scale);
	pos_buff = 0;
	time_scale_tmp = 0;
	Switch_timer_DAC_IRQ(ENABLE);
}

/*
 * ************************************************************
 * below is IRQhandler functions
 * ************************************************************
 */
void TIM4_IRQHandler(void) {
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET) {
		if (flag_play_wav == 0) {
			DAC_SetChannel1Data(DAC_Align_12b_R, dac_buff[pos_buff++]);
			if (pos_buff >= count_buff_element) {
				pos_buff = 0;
			}
		} else {
			if (WAV_Buff_out != WAV_Buff_in) {
				uint16_t val = get_buffer();
//				if (val <= 4000) {
					DAC_SetChannel1Data(DAC_Align_12b_R, val);
//				}
			}
			if (flag_EndOfFile == 1) {
				flag_play_wav = 0;
			}
		}
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
	}
}

/*
 * ************************************************************
 * below is IRQhandler functions
 * ************************************************************
 */
void TIM7_IRQHandler(void) {
	if (TIM_GetITStatus(TIM7, TIM_IT_Update) == SET) {
		if (flag_play_wav == 1) {
			add_buffer(ReadWAVFile(WAV_info_play, &flag_EndOfFile));
		}
		TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
	}
}
